#include "chemnitz_stream.h"

static void replenish (CHEMNITZ_STREAM stream)
	/*@modifies stream@*/;

static void replenish (CHEMNITZ_STREAM stream)
{
	uint8_t state [BYTES_PER_BLOCK];
	halfblock_t *halves;
	halves = (halfblock_t *) state;
	memset (state, 0, BYTES_PER_BLOCK);
	memset (stream->buffer, 0, BYTES_PER_BLOCK);
	halves [0] = stream->iv;
	halves [1] = stream->ctr;
	chemnitz_encrypt (state, stream->key, stream->buffer);
	stream->ctr = stream->ctr + 1;
}

CHEMNITZ_STREAM chemnitz_stream_open (const uint8_t const *key, const uint64_t iv)
{
	CHEMNITZ_STREAM stream;
	stream = (CHEMNITZ_STREAM) malloc (sizeof (*stream));
	if (stream)
	{
		memset (stream->buffer, 0, BYTES_PER_BLOCK);
		stream->ctr = 0;
		stream->iv = iv;
		stream->index = 0;
		memcpy (stream->key, key, 16);
		replenish (stream);
		return stream;
	}
	else
	{
		return 0;
	}
}

bool chemnitz_stream_is_open (const CHEMNITZ_STREAM stream)
{
	if (stream)
	{
		return true;
	}
	else
	{
		return false;
	}
}

size_t chemnitz_stream_read (CHEMNITZ_STREAM stream, uint8_t *buffer, size_t count)
{
	size_t i;
	memset (buffer, 0, count);
	for (i = 0; i < count; i ++)
	{
		buffer [i] = stream->buffer [stream->index];
		stream->index = (stream->index + 1) & BLOCK_MASK;
		if (stream->index == 0)
		{
			replenish (stream);
		}
	}
	return i;
}

void chemnitz_stream_close (CHEMNITZ_STREAM stream)
{
	if (stream)
	{
		free (stream);
	}
}

